package commons.base.luncene;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
//import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class IndexDir {

	protected Analyzer analyzer;
	protected Directory directory;
	
	protected Updater updater;
	
	public IndexDir(String indexPath) throws IOException{
		directory = FSDirectory.open(Paths.get(indexPath));
//		analyzer = new SmartChineseAnalyzer();
		
		updater = new Updater(this);
	}
	
	public void close(){
		if(updater != null){
			try {
				updater.commit();
				updater.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public List<Document> search(String field, String regex, int n)throws IOException, ParseException{
		List<Document> list = new ArrayList<Document>();
		
		Searcher searcher = null;
		try{
			searcher = getSearcher();
			list = searcher.search(field, regex, n);
		}finally {
			if(searcher != null) searcher.close();
		}
		
		return list;
	}
	
	public Updater getUpdater() {
		return updater;
	}

	public Searcher getSearcher() throws IOException {
		updater.flush();
		return new Searcher(this);
	}

	public static class Updater{
		protected IndexWriter writer;

		public Updater(IndexDir indexDir) throws IOException {
			IndexWriterConfig iwc = new IndexWriterConfig(indexDir.analyzer);
			iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
			
			this.writer = new IndexWriter(indexDir.directory, iwc);
		}
		
		public Updater deleteAll() throws IOException{
			writer.deleteAll();
			return this;
		}
		
		/**
		 * 删除正则匹配的doc
		 * @param field
		 * @param regex
		 * @throws IOException 
		 */
		public Updater delete(String field, String regex) throws IOException{
			Query query = new RegexpQuery(new Term(field, regex));
			
			writer.deleteDocuments(query);
			return this;
		}
		
		public Updater addDocument(Document doc) throws IOException{
			writer.addDocument(doc);
			return this;
		}
		
		public Updater updateDocument(String field, String value, Document doc) throws IOException{
			writer.updateDocument(new Term(field, value), doc);
			return this;
		}
		
		public Updater commit() throws IOException{
			writer.commit();
			return this;
		}
		
		public Updater flush() throws IOException{
			writer.flush();
			return this;
		}
		
		public void close() throws IOException{
			if(writer != null){
				writer.commit();
				writer.close();
			}
		}
	}
	
	public static class Searcher{
		private IndexReader reader;
		private IndexSearcher searcher;
		private IndexDir indexDir;
		
		public Searcher(IndexDir indexDir) throws IOException{
			this.indexDir = indexDir;
			
			checkIndexReader();
		}
		
		private boolean checkIndexReader() throws IOException{
			if(reader != null){
				return true;
			}
			
			if(indexDir.directory != null){
				if(DirectoryReader.indexExists(indexDir.directory)){
//					reader = DirectoryReader.open(indexDir.directory);
					reader = DirectoryReader.open(indexDir.updater.writer);
					searcher = new IndexSearcher(reader);
					return true;
				}
			}
			
			return false;
		}
		
		public void close() throws IOException{
			if(reader != null){
				reader.close();
			}
		}
		
		public List<Document> search(String field, String regex, int n)throws IOException, ParseException{
			List<Document> list = new ArrayList<Document>();
			
			if(!checkIndexReader()){
				return list;
			}
			
			// 正则表达式模糊查询
			Query query = new RegexpQuery(new Term(field, regex));
			
			TopDocs results = searcher.search(query, n);
			for(ScoreDoc scoreDoc : results.scoreDocs){
				list.add(searcher.doc(scoreDoc.doc));
			}
			
			return list;
		}
	}
}
